package org.flown.util.jdbc;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


/**
 * 不支持aspect
 * <p>
 * 	<bean id="MyBatisUtil" class="org.flown.utils.MyBatisUtil">
 * 		<property name="SqlSessionFactory" ref="factory">
 * 	</bean>
 * <p>
 * 	<bean id="MyBatisUtil" class="org.flown.utils.MyBatisUtil">
 * 		<property name="ConfigLocation" value="mybatis.xml">
 * 	</bean>
 * <p>
 * MyBatisUtil.getMapper("UserMapper");
 * 
 * @author weifei(flown)
*/
public class MyBatisUtil
{
    private static SqlSessionFactory sql_session_factory;
    private static SqlSession sql_session;

    public MyBatisUtil(){super();}
    public MyBatisUtil(SqlSessionFactory factory){this.setSqlSessionFactory(factory);}
    public MyBatisUtil(String mybatis_config_path){this.setConfigLocation(mybatis_config_path);}
    public void setSqlSessionFactory(SqlSessionFactory factory){MyBatisUtil.init(factory);}
    public void setConfigLocation(String classpath){MyBatisUtil.init(classpath);}


    public static void init(SqlSessionFactory factory)
    {
        MyBatisUtil.sql_session_factory = factory;
        MyBatisUtil.sql_session = MyBatisUtil.sql_session_factory.openSession(true);
    }
    public static void init(String mybatis_config_classpath)
    {
        try
        {
            InputStream resource = Resources.getResourceAsStream(mybatis_config_classpath);
            MyBatisUtil.sql_session_factory = new SqlSessionFactoryBuilder().build(resource);
            MyBatisUtil.sql_session = MyBatisUtil.sql_session_factory.openSession(true);
        }
        catch (IOException e) {e.printStackTrace();}
    }


    public static <T> T getMapper(Class<T> interface_class)
    {
        if (MyBatisUtil.sql_session_factory != null)
            return null;
        return MyBatisUtil.sql_session.getMapper(interface_class);
    }


    public static void close(){MyBatisUtil.closeSession();}
    public static void closeSession()
    {
        if (MyBatisUtil.sql_session != null)
            MyBatisUtil.sql_session.close();
    }


    private static <T> Object invokeMethod(String class_name, String method_name, Object... parameters)
    {
        Object object = null;
        try
        {
            int count = parameters.length;
            Class<?>[] parameters_class = new Class<?>[count];
            for (int i = 0; i < count; i++)
            {
                parameters_class[i] = parameters[i].getClass();
            }
            Object instance = Class.forName(class_name).getDeclaredConstructor().newInstance();
            Method method = instance.getClass().getMethod(method_name, parameters_class);
            object = method.invoke(instance, parameters);
        }
        catch (ClassNotFoundException | InstantiationException | InvocationTargetException | IllegalAccessException |
               SecurityException | NoSuchMethodException | IllegalArgumentException e) {e.printStackTrace();}

        return object;
    }


    private static <T> Object invokeMethod(T instance, String method_name, Object... parameters)
    {
        Object object = null;
        try
        {
            int count = parameters.length;
            Class<?>[] parameters_class = new Class<?>[count];
            for (int i = 0; i < count; i++)
            {
                parameters_class[i] = parameters[i].getClass();
            }
            Method method = instance.getClass().getMethod(method_name, parameters_class);
            object = method.invoke(instance, parameters);
        }
        catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | SecurityException e) {e.printStackTrace();}
        return object;
    }


    /**
     * 配置了mapper的接口类可以不用写实现类，直接调用这个方法
     * @param interface_class 配置了mapper的接口类
     * @param method_name 要调用的方法名
     * @param parameter 参数
     */
    public static <T> Object invokeMapperMethod(Class<T> interface_class, String method_name, Object parameter)
    {
        T interface_instance = MyBatisUtil.sql_session.getMapper(interface_class);
        return MyBatisUtil.invokeMethod(interface_instance, method_name, parameter);
    }



    public static Object selectOne(String method_full_name)
    {
        return  MyBatisUtil.sql_session.selectOne(method_full_name);
    }
    public static Object selectOne(String method_full_name, Object parameter)
    {
        return MyBatisUtil.sql_session.selectOne(method_full_name, parameter);
    }


    public static void insert(String method_full_name)
    {
        MyBatisUtil.sql_session.insert(method_full_name);
    }
    public static void insert(String method_full_name, Object parameter)
    {
        MyBatisUtil.sql_session.insert(method_full_name, parameter);
    }


    public static void update(String method_full_name)
    {
        MyBatisUtil.sql_session.update(method_full_name);
    }
    public static void update(String method_full_name, Object parameter)
    {
        MyBatisUtil.sql_session.update(method_full_name, parameter);
    }


    public static void delete(String method_full_name)
    {
        MyBatisUtil.sql_session.delete(method_full_name);
    }
    public static void delete(String method_full_name, Object parameter)
    {
        MyBatisUtil.sql_session.delete(method_full_name, parameter);
    }
}

